package it.gtd.swimpool.model.business;

import com.mysema.query.BooleanBuilder;
import com.mysema.query.jpa.impl.JPAQuery;
import it.gtd.swimpool.model.entity.*;
import org.jetbrains.annotations.Nullable;

import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

@Stateless
@LocalBean
public class LookupManager {
    @PersistenceContext
    private EntityManager entityManager;

//    public Collection<User> searchForHelp(Collection<Skill> skills, @Nullable Collection<User> users, @Nullable Rating minRating, @Nullable Integer resultsNumber, @Nullable Integer startIndex) {
//        checkNotNull(skills);
//        checkArgument(!skills.isEmpty(), "Skills set can't be empty");
//        for (Skill skill : skills) {
//            checkNotNull(skill);
//            checkArgument(entityManager.contains(skill), "EM doesn't contains skill " + skill.getName());
//        }
//
//        JPAQuery query = new JPAQuery(entityManager);
//        QUser userModel = QUser.user;
//        QFeedback feedbackModel = QFeedback.feedback;
//        query = query.from(feedbackModel).rightJoin(feedbackModel.composed().target(), userModel);
//
//        BooleanBuilder expression = new BooleanBuilder();
//
//        BooleanBuilder skillsExpression = new BooleanBuilder();
//        for (Skill skill : skills) {
//            skillsExpression.or(userModel.skills.contains(skill));
//        }
//        expression.and(skillsExpression);
//
//        if (null != users && !users.isEmpty()) {
//            BooleanBuilder usersExpression = new BooleanBuilder();
//            for (User user : users) {
//                usersExpression.or(userModel.eq(user));
//            }
//            expression.and(usersExpression);
//        }
//
//        if (null != minRating) {
//            expression.and(feedbackModel.rating.gt(minRating).or(feedbackModel.rating.eq(minRating)));
//        }
//
//        if (null != resultsNumber) {
//            query = query.limit(resultsNumber);
//        }
//
//        if (null != startIndex) {
//            query = query.offset(startIndex);
//        }
//
//        query = query.where(expression);
//
//        return query.list(userModel);
//    }

    public Collection<User> searchForHelp(Collection<Skill> skills, @Nullable Collection<User> users, @Nullable Rating minRating, @Nullable Integer resultsNumber, @Nullable Integer startIndex) {
        checkNotNull(skills, "skills can't be null");
        checkArgument(!skills.isEmpty(), "Skills set can't be empty");
        for (Skill skill : skills) {
            checkNotNull(skill);
            checkArgument(entityManager.contains(skill), "EM doesn't contains skill " + skill.getName());
        }

        List<User> matchedUsers;

        if (null != users) {
            matchedUsers = new ArrayList<User>();
            for (User user : users) {
                Collection<Skill> userSkills = user.getSkills();
                for (Skill skill : skills) {
                    if (userSkills.contains(skill)) {
                        matchedUsers.add(user);
                        break;
                    }
                }
            }
        } else {
            JPAQuery query = new JPAQuery(entityManager);
            QUser userModel = QUser.user;
            QSkill skillModel = QSkill.skill;

            query.from(userModel).from(skillModel);
            query.where(skillModel.in(skills).and(skillModel.in(userModel.skills)));

            if (minRating == null) {
                if (startIndex != null) {
                    query.offset(startIndex);
                }

                if (resultsNumber != null) {
                    query.limit(resultsNumber);
                }

                return query.list(userModel);
            }

            matchedUsers = query.list(userModel);
        }

        if (minRating == null) {
            return matchedUsers;
        }

        List<User> proficientUsers = new ArrayList<User>();
        int start = (startIndex != null) ? startIndex : 0;
        int count = (resultsNumber != null) ? resultsNumber : Integer.MAX_VALUE;
        int index = 0;

        for (User user : matchedUsers) {
            Collection<Skill> userSkills = user.getSkills();

            JPAQuery query = new JPAQuery(entityManager);
            QUser userModel = QUser.user;
            QFeedback feedbackModel = QFeedback.feedback;

            query = query.from(feedbackModel).join(feedbackModel.composed().target(), userModel);

            BooleanBuilder expression = new BooleanBuilder();
            expression.and(feedbackModel.composed().target().eq(user));
            expression.and(feedbackModel.composed().skill().in(skills));
            expression.and(feedbackModel.rating.goe(minRating));

            query.where(expression);

            if (query.exists()) {
                if (index >= start) {
                    proficientUsers.add(user);
                }
                if (proficientUsers.size() >= count) {
                    break;
                }
                index++;
            }
        }

        return proficientUsers;
    }


    public Collection<User> lookupUsers(@Nullable Integer resultsNumber, @Nullable Integer startIndex, @Nullable String partialName) {
        JPAQuery query = new JPAQuery(entityManager);
        QUser user = QUser.user;
        query = query.from(user);

        if (null != resultsNumber) {
            query = query.limit(resultsNumber);
        }

        if (null != startIndex) {
            query = query.offset(startIndex);
        }

        if (null != partialName) {
            query = query.where(user.name.like("%" + partialName + "%"));
        }

        return query.list(user);
    }
}
